/**
 * 
 */
package com.aaron.client;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Widget;


import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.ClickListener;

import org.gwtwidgets.client.ui.ImageButton;
import java.util.*;

/**
 * Widget to display and modify a project's owners, collaborators, and viewers 
 * @author aaron
 *
 */
public class CollaboratePanel extends Composite {
	/**
	 * Widget to display a titled list
	 * @author aaron
	 *
	 */
	private class ListPanel extends Composite{
		private VerticalPanel panel;
		private VerticalPanel list;
		/**
		 * 
		 * @param title The title of the list
		 */
		public ListPanel(String title){
			panel=new VerticalPanel();
			list=new VerticalPanel();
			initWidget(panel);
			panel.add(new Label(title));
			panel.add(list);
			this.addStyleName("list-box");
		}
		/**
		 * Add a text element to the bottom of the list
		 * @param text The text to add
		 */
		public void addItem(String text){
			Label item=new Label(text);
			item.addStyleName("list-box-item");
			list.add(item);
		}
		/**
		 * Remove a text element from the list
		 * @param text The text to remove
		 */
		public void removeItem(String text){
			Iterator itr=list.iterator();
			while(itr.hasNext()){
				Label label=(Label)itr.next();
				if(label.getText()==text){
					list.remove(label);
				}
			}
		}
		/**
		 * Remove all elements from the list. Keep the title.
		 *
		 */
		public void removeAll(){
			panel.remove(list);
			list=new VerticalPanel();
			panel.add(list);
			
		}
	}
	/**
	 * Widget to modify owners, collaborators, and viewers and send this information back to the server.
	 * @author aaron
	 *
	 */
	private class ModifyCollaboratorsPanel extends Composite{
		/**
		 * Widget for each owner, collaborator, or viewer.
		 * Contains a textbox for modifying the collaborator's email,
		 * a dropdown for editing their association with the project,
		 * and a button to remove them from the project.
		 * @author aaron
		 *
		 */
		private class CollaboratorEntry extends Composite{
			private TextBox username_textbox;
			private ListBox association_listbox;
			private ImageButton remove_button;
			private HorizontalPanel items;
			private Label label=new Label("@gmail.com");
			/**
			 * @param collaborator The collaborator information to use when filling in the textbox and dropdown widgets. 
			 */
			public CollaboratorEntry(Collaborator collaborator){
				items=new HorizontalPanel();
				username_textbox=new TextBox();
				username_textbox.setText(collaborator.getUsername());
				association_listbox=new ListBox();
				association_listbox.addItem("owner");
				association_listbox.addItem("collaborator");
				association_listbox.addItem("viewer");
				if(collaborator.getAssociation()=="owner"){
					association_listbox.setSelectedIndex(0);
				}
				if(collaborator.getAssociation()=="collaborator"){
					association_listbox.setSelectedIndex(1);
				}
				if(collaborator.getAssociation()=="viewer"){
					association_listbox.setSelectedIndex(2);
				}
				remove_button=new ImageButton("icons/delete.png", 16 ,16);
				remove_button.addStyleName("remove-button");
				remove_button.setBorderOnWidth(0);
				class RemoveListener implements ClickListener{
					private Widget parent;
					public RemoveListener(Widget parent){
						this.parent=parent;
					}
					public void onClick(Widget sender){
						list.remove(parent);
					}
				}
				remove_button.addClickListener(new RemoveListener(this));
				items.add(username_textbox);
				items.add(label);
				items.add(association_listbox);
				items.add(remove_button);
				initWidget(items);
			}
			/**
			 * Create a blank collaborator entry.
			 *
			 */
			public CollaboratorEntry(){
				items=new HorizontalPanel();
				username_textbox=new TextBox();
				association_listbox=new ListBox();
				association_listbox.addItem("collaborator");
				association_listbox.addItem("viewer");
				remove_button=new ImageButton("icons/delete.png", 16 ,16);
				remove_button.addStyleName("remove-button");
				remove_button.setBorderOnWidth(0);
				class RemoveListener implements ClickListener{
					private Widget parent;
					public RemoveListener(Widget parent){
						this.parent=parent;
					}
					public void onClick(Widget sender){
						list.remove(parent);
					}
				}
				remove_button.addClickListener(new RemoveListener(this));
				items.add(username_textbox);
				items.add(label);
				items.add(association_listbox);
				items.add(remove_button);
				initWidget(items);
			}
			public Collaborator getCollaborator(){
				return new Collaborator(username_textbox.getText(), association_listbox.getValue(association_listbox.getSelectedIndex()));
			}
		}
		private ArrayList contacts;
		private VerticalPanel panel;
		private VerticalPanel list;
		private ImageButton add_button;
		private ImageButton apply_button;
		/**
		 * 
		 * @param contacts List of the user's contacts 
		 * @param collaborators List of collaborators already associated with this project.
		 */
		public ModifyCollaboratorsPanel(ArrayList contacts, ArrayList collaborators){
			this.contacts=contacts;
			panel=new VerticalPanel();
			list=new VerticalPanel();
			add_button=new ImageButton("icons/add.png", 16, 16);
			add_button.addStyleName("add-button");
			add_button.setBorderOnWidth(0);
			add_button.addClickListener(new ClickListener(){
				public void onClick(Widget sender){
					list.insert(new CollaboratorEntry(), list.getWidgetIndex(sender));
				}
			});
			list.add(add_button);

			//apply button sends new collaborator information to server via rpc
			apply_button=new ImageButton("icons/accept.png", 16, 16);
			apply_button.addStyleName("apply-button");
			apply_button.setBorderOnWidth(0);
			apply_button.addClickListener(new ClickListener(){
				public void onClick(Widget sender){
					ProjectServiceAsync project_service=ProjectService.Util.getInstance();
					project_service.setCollaborators(getCollaborators(), project_name, auth, new AsyncCallback(){
						public void onSuccess(Object result){
							updateLists();
						}
						public void onFailure(Throwable t){
							Window.alert("Unable to update collaborators");
						}
					});
					
				}
			});
			
			panel.add(new Label("Modify"));
			panel.add(list);
			panel.add(apply_button);
			
			Iterator itr=collaborators.iterator();
			while(itr.hasNext()){
				Collaborator collaborator=(Collaborator)itr.next();
				//add collaborator to list
				list.insert(new CollaboratorEntry(collaborator), 0);
			}
			initWidget(panel);
			this.addStyleName("list-box");
		}
		/**
		 * 
		 * @return A list of owners, collaborators, and viewers as is currently displayed
		 */
		public ArrayList getCollaborators(){
			ArrayList collaborators=new ArrayList();
			Iterator itr=list.iterator();
			while(itr.hasNext()){
				try{
					Object obj=itr.next();
					//Don't want to try to cast the + button into an entry
					if(obj instanceof CollaboratorEntry){
						CollaboratorEntry entry=(CollaboratorEntry)obj;
						//remove whitespace
						if(entry.getCollaborator().getUsername().trim()!=""){
							collaborators.add(entry.getCollaborator());
						}
					}
				}
				catch(ClassCastException e){
					//Window.alert("ModifyCollaboratorsPanel.getCollaborators: unable to cast to CollaboratorEntry");
				}
			}
			return collaborators;
			
		}
		
	}
	
	//model
	private String project_name;
	private String auth;
	private User user;
	private ArrayList collaborators;
	private ArrayList viewers;
	
	//view
	private HorizontalPanel panel;
	private ListPanel owners_panel;
	private ListPanel collaborators_panel;
	private ListPanel viewers_panel;
	private ModifyCollaboratorsPanel modify_panel;
	
	/**
	 * 
	 * @param project_name The name of the project
	 * @param auth Session key
	 */
	public CollaboratePanel(String project_name, String auth){
		this.project_name=project_name;
		this.auth=auth;
		panel=new HorizontalPanel();
		owners_panel=new ListPanel("Owner");
		collaborators_panel=new ListPanel("Collaborators");
		viewers_panel=new ListPanel("Viewers");
		
		panel.add(owners_panel);
		panel.add(collaborators_panel);
		panel.add(viewers_panel);
		
		//get the user object from server
		UserServiceAsync sessionService =UserService.Util.getInstance();
		sessionService.getUser(auth, new AsyncCallback(){
			public void onSuccess(Object result){
				user=(User)result;
			}
			public void onFailure(Throwable caught) {
				Window.alert("Unable to fetch user information.");
			}
		});
		
		//get collaborators from server
		ProjectServiceAsync projectService=ProjectService.Util.getInstance();
		projectService.getCollaborators(project_name, auth, new AsyncCallback(){
			public void onSuccess(Object result){
				try{
					collaborators=(ArrayList)result;
					modify_panel=new ModifyCollaboratorsPanel(new ArrayList(), collaborators);
					panel.add(modify_panel);
					updateLists();
				}
				catch(ClassCastException e){
					Window.alert("projectService.getCollaborators:onSuccess: unable to cast to ArrayList");
				}
			}
			public void onFailure(Throwable caught) {
				collaborators=null;
				Window.alert("Unable to fetch collaborators.");
			}
		});
		initWidget(panel);
	}
	/**
	 * Updates owners, collaborators, and viewers ListPanels with the newly modified owners, collaborators, and viewers
	 *
	 */
	private void updateLists(){
		//clear the current list panels
		owners_panel.removeAll();
		collaborators_panel.removeAll();
		viewers_panel.removeAll();
		
		//update the listpanels with new collaborator information
		ArrayList new_collaborators=modify_panel.getCollaborators();
		Iterator itr=new_collaborators.iterator();
		while(itr.hasNext()){
			try{
				Collaborator collaborator=(Collaborator)itr.next();

				if(collaborator.getAssociation()=="collaborator"){
					collaborators_panel.addItem(collaborator.getUsername());
				}
				else if(collaborator.getAssociation()=="viewer"){
					viewers_panel.addItem(collaborator.getUsername());
				}
				else if(collaborator.getAssociation()=="owner"){
					owners_panel.addItem(collaborator.getUsername());
				}
			}
			catch(ClassCastException e){
				Window.alert("updateLists:Unable to cast to Collaborator");
			}
		}
	}
}
